package com.wondersgroup.app.util;

import java.util.Date;

import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;

import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;

import com.nimbusds.jose.JOSEException;
import com.nimbusds.jose.JWSVerifier;
import com.nimbusds.jose.crypto.MACVerifier;
import com.nimbusds.jwt.EncryptedJWT;
import com.nimbusds.jwt.JWT;
import com.nimbusds.jwt.JWTClaimsSet;
import com.nimbusds.jwt.PlainJWT;
import com.nimbusds.jwt.SignedJWT;

public class JWTAuthenticationProvider implements AuthenticationProvider {
    
    private JWSVerifier verifier;
    
    public static void main(String[] args) {
		System.out.println("pFETsq6yEhgFLXZhuAPUZ{Q3B2RNW7en".length());
	}
    
    public JWTAuthenticationProvider() throws JOSEException {
    	SecretKey secretKey = new SecretKeySpec("pFETsq6yEhgFLXZhuAPUZ{Q3B2RNW7en".getBytes(), "AES");
        this.verifier = new MACVerifier(secretKey);
    }

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        JWTToken jwtToken = (JWTToken) authentication;
        JWT jwt = jwtToken.getJwt();
        
        // Check type of the parsed JOSE object
        if (jwt instanceof PlainJWT) {
            handlePlainToken((PlainJWT) jwt);
        } else if (jwt instanceof SignedJWT) {
            handleSignedToken((SignedJWT) jwt);
        } else if (jwt instanceof EncryptedJWT) {
            handleEncryptedToken((EncryptedJWT) jwt);
        }
        
        Date referenceTime = new Date();
        JWTClaimsSet claims = jwtToken.getClaims();
        
        Date expirationTime = claims.getExpirationTime();
        if (expirationTime == null || expirationTime.before(referenceTime)) {
        	
            throw new JwtAuthenticationException("The token is expired");
        }
        
//        Date notBeforeTime = claims.getNotBeforeTime();
//        if (notBeforeTime == null || notBeforeTime.after(referenceTime)) {
//            throw new JwtAuthenticationException("Not before is after sysdate");
//        }
        
//        String issuerReference = "my.site.com";
//        String issuer = claims.getIssuer();
//        if (!issuerReference.equals(issuer)) {
//            throw new JwtAuthenticationException("Invalid issuer");
//        }
        
        jwtToken.setAuthenticated(true);
        return jwtToken;
    }

    @Override
    public boolean supports(Class<?> authentication) {
        return JWTToken.class.isAssignableFrom(authentication);
    }
    
    private void handlePlainToken(PlainJWT jwt) {
        throw new JwtAuthenticationException("Unsecured plain tokens are not supported");
    }
    
    private void handleSignedToken(SignedJWT jwt) {
        try {
            if (!jwt.verify(verifier)) {
                throw new JwtAuthenticationException("Signature validation failed");
            }
        } catch (JOSEException e) {
            throw new JwtAuthenticationException("Signature validation failed");
        }
    }
    
    private void handleEncryptedToken(EncryptedJWT jwt) {
        throw new UnsupportedOperationException("Unsupported token type");
    }
    
}